#pragma once
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <iostream>
#include <arpa/inet.h>
#include <cstdio>
#include <cstring>
#include <pthread.h>

class UdpClient
{
public:
    UdpClient(uint16_t port, const std::string &ip) : _port(port), _svr_ip(ip) {}
    ~UdpClient() { close(_sock); }

    void init()
    {
        // 套接字创捷
        _sock = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sock < 0)
        {
            std::cout << "create socket failed...." << std::endl;
            abort();
        }
    }

    // 线程执行函数，负责接收消息
    static void *RecvMessageThread(void *args)
    {
        while (1)
        {
            int *sock = (int *)args; //提取sock套接字

            // 收服务器广播来的消息
            char recvbuff[1024 * 4] = {0};
            recvfrom(*sock, recvbuff, sizeof recvbuff - 1, 0, nullptr, nullptr);
            // 打印回收到的消息
            std::cout << recvbuff << std::endl;
        }
        return nullptr;
    }
    void start()
    {
        // 创建服务器的 sockaddr结构
        struct sockaddr_in svr;
        svr.sin_port = htons(_port);
        svr.sin_addr.s_addr = inet_addr(_svr_ip.c_str());
        svr.sin_family = AF_INET;

        // 发送消息的缓冲区
        char sendbuff[1024] = {0};

        // 创建一个线程来接收别人发送的信息
        pthread_t tid;
        pthread_create(&tid, nullptr, RecvMessageThread, (void *)&_sock);

        // 该线程负责发送消息
        while (1)
        {
            // 输入消息
            std::cerr << "Enrty # ";
            fgets(sendbuff, sizeof sendbuff - 1, stdin);
            sendbuff[strlen(sendbuff) - 1] = 0;
            std::string message = sendbuff;
            // 发送消息
            sendto(_sock, message.c_str(), message.size(), 0, (struct sockaddr *)&svr, sizeof svr);
        }
    }

private:
    int _sock;
    uint16_t _port;
    std::string _svr_ip;
};